/*
# PostgreSQL Database Modeler (pgModeler)
#
# Copyright 2006-2018 - Raphael Araújo e Silva <raphael@pgmodeler.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# The complete text of GPLv3 is at LICENSE file on source code root directory.
# Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
*/

/**
\ingroup libpgmodeler
\class BaseRelationship
\brief Implements the basic operations to manipulate relationships between tables
\note <strong>Creation date:</strong> 09/04/2008
*/

#ifndef BASE_RELATIONSHIP_H
#define BASE_RELATIONSHIP_H

#include "table.h"
#include "textbox.h"
#include "schema.h"
#include <cmath>
#include <QColor>

class BaseRelationship: public BaseGraphicObject  {
	protected:
		//! \brief This attribute stores the foreign key used to generate the relationship (only for FK relationships)
		Constraint *reference_fk;

		//! \brief This attribute overrides the default color configuration for relationship line and descriptor
		QColor custom_color;

		//! \brief Represents the points added by the user on the relationship line
		vector<QPointF> points;

		//! \brief Indicates whether the relationship is linked to the tables
		bool connected;

		//! \brief Indicates the mandatory participation of source and destination tables
		bool dst_mandatory, src_mandatory;

		/*! \brief Relationship lables:
		 0 - Source cardinality
		 1 - Destination cardinality
		 2 - Relationship name */
		Textbox *lables[3];

		/*! \brief Stores the distances of the labels from its respectively origins.
		 This is used to controle de position of the labels when they are
		 moved by the user */
		QPointF lables_dist[3];

		//! \brief Entities envolved on the relationship
		BaseTable *src_table,
		*dst_table;

		/*! \brief Relationship type. It can be "One to One", "One to Many", "Many to Many",
		 "Generalization", "Dependecy". The constants RELATIONSHIP_??? are used
		 to assign a type to the relationship */
		unsigned rel_type;

		//! \brief Sets the attributes used on the generation of XML definition for relationship
		void setRelationshipAttributes(void);

		//! \brief Makes the initial configuration creating the labels
		void configureRelationship(void);

		//! \brief Marks the flag indicating that relationship is connected
		void connectRelationship(void);

		//! \brief Uncheck the flag indicating that relationship is disconnected
		void disconnectRelationship(void);

		//! \brief Toggles the connected flag and forces the tables/schemas/relationship update
		void setConnected(bool value);

		QString getCachedCode(unsigned def_type);

		virtual QString getDropDefinition(bool) final { return(""); }

	protected:
		void setReferenceForeignKey(Constraint *reference_fk);
		Constraint *getReferenceForeignKey(void);

	public:
		//! \brief Constants used to assign the type to relationship
		static const unsigned RELATIONSHIP_11=10, //! \brief One to one
		RELATIONSHIP_1N=11, //! \brief One to many
		RELATIONSHIP_NN=12, //! \brief Many to many
		RELATIONSHIP_GEN=13, //! \brief Generalization (Inheritance)
		RELATIONSHIP_DEP=14, //! \brief Dependency (table-view) / Copy (table-table)
		RELATIONSHIP_FK=15; //! \brief Relationship generated by creating a foreign key manually on a table

		//! \brief Constats used to reference the relationship labels
		static const unsigned SRC_CARD_LABEL=0,
		DST_CARD_LABEL=1,
		REL_NAME_LABEL=2;

		//! \brief Constants used to reference the source and destination tables
		static const unsigned SRC_TABLE=0,
		DST_TABLE=1;

		BaseRelationship(BaseRelationship *rel);

		BaseRelationship(unsigned rel_type, BaseTable *src_tab, BaseTable *dst_tab, bool dst_mandatory, bool src_mandatory);

		~BaseRelationship(void);

		//! \brief Sets the name of the relationship
		void setName(const QString &name);

		//! \brief Sets the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE)
		void setMandatoryTable(unsigned table_id, bool value);

		//! \brief Return one relationship label using its id (Via constants LABEL_???)
		Textbox *getLabel(unsigned label_id);

		//! \brief Returns one of the participant tables (Via constants SRC_TABLE | DST_TABLE)
		BaseTable *getTable(unsigned table_id);

		//! \brief Returns the relationship type
		unsigned getRelationshipType(void);

		//! \brief Returns the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE)
		bool isTableMandatory(unsigned table_id);

		//! \brief Returns the relationship connection state
		bool isRelationshipConnected(void);

		/*! \brief Since base relationships doesn't has SQL code definition this method will return a empty
		definition whenever the user try to generate a SQL for this object. */
		virtual QString getCodeDefinition(unsigned def_type);

		//! \brief Returns whether the table is linked to itself via relationship (self-relationship)
		bool isSelfRelationship(void);

		//! \brief Stores the points that defines the custom relationship line
		void setPoints(const vector<QPointF> &points);

		//! \brief Returns the relationship point list
		vector<QPointF> getPoints(void);

		//! \brief Sets the distance of the specified label in relation to its origin
		void setLabelDistance(unsigned label_id, QPointF label_dist);

		//! \brief Gets the distance of the specified label in relation to its origin
		QPointF getLabelDistance(unsigned label_id);

		void setCustomColor(const QColor &color);

		QColor getCustomColor(void);

		void resetLabelsDistance(void);

		//! \brief Assigns one relationship to other making the appropriate attribute copy
		void operator = (BaseRelationship &rel);

		QString getRelTypeAttribute(void);

		virtual void setCodeInvalidated(bool value);

		virtual QString getAlterDefinition(BaseObject *) { return(""); }

		friend class DatabaseModel;
		friend class RelationshipWidget;
		friend class ModelWidget;
};

#endif
